package com.net.xpay.common.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayFundFlexiblestaffingAuthenticationApplyModel;
import com.alipay.api.domain.AlipayFundFlexiblestaffingAuthenticationQueryModel;
import com.alipay.api.domain.ParticipantDTO;
import com.alipay.api.response.AlipayFundFlexiblestaffingAuthenticationApplyResponse;
import com.alipay.api.response.AlipayFundFlexiblestaffingAuthenticationQueryResponse;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.net.xpay.common.domain.FlexibleStaffAuthentication;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.notify.FlexibleStaffAuthenticationNotifyRecord;
import com.net.xpay.common.enums.notify.NotifyStatus;
import com.net.xpay.common.manager.FlexibleStaffAuthenticationManager;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.model.ApplyFlexibleStaffAuthenticationModel;
import com.net.xpay.common.validator.FlexibleStaffAuthenticationValidator;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.dto.FlexibleStaffAuthenticationDto;
import com.net.xpay.core.enums.CardStatus;
import com.net.xpay.core.helper.SignerCheckHelper;
import com.net.xpay.core.utils.GenIdUtil;
import com.net.common.exception.BusinessException;
import com.net.common.util.HttpClientUtil;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.SerializationUtil;
import com.net.xpay.alipay.safePay.PoseidonSafePayAlipayClient;
import com.net.xpay.common.manager.notify.FlexibleStaffAuthenticationNotifyRecordManager;
import com.net.xpay.common.service.FlexibleStaffAuthenticationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class FlexibleStaffAuthenticationServiceImpl implements FlexibleStaffAuthenticationService {

    @Autowired
    private FlexibleStaffAuthenticationValidator flexibleStaffAuthenticationValidator;

    @Autowired
    private PoseidonSafePayAlipayClient xpaySafePayAlipayClient;

    @Autowired
    private FlexibleStaffAuthenticationManager flexibleStaffAuthenticationManager;

    @Autowired
    private UserManager userManager;

    @Autowired
    private SignerCheckHelper signerCheckHelper;

    @Autowired
    private FlexibleStaffAuthenticationNotifyRecordManager flexibleStaffAuthenticationNotifyRecordManager;

    @Override
    public FlexibleStaffAuthentication applyFlexibleStaffAuthentication(User user, ApplyFlexibleStaffAuthenticationModel model) {
        flexibleStaffAuthenticationValidator.validateApplyFlexibleStaffAuthentication(user, model);

        FlexibleStaffAuthentication authentication = buildAuthentication(user, model);

        doApplyFlexibleStaffAuthentication(authentication);

        flexibleStaffAuthenticationManager.save(authentication);
        return authentication;
    }

    @Override
    public void updateFlexibleStaffAuthenticationCardInfo(String outBizNo, String employeeCardNo, String alipayLogonId, String alipayUid) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(outBizNo) && !Strings.isNullOrEmpty(employeeCardNo));
        FlexibleStaffAuthentication authentication = flexibleStaffAuthenticationManager.getByOutBizNo(outBizNo);
        if (authentication == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "视频核验不存在");
        }

        authentication.setEmployeeCardNo(employeeCardNo);
        authentication.setAlipayLogonId(alipayLogonId);
        authentication.setAlipayUid(alipayUid);
        authentication.setOpenCardTime(LocalDateTime.now());
        authentication.setCardStatus(CardStatus.YES);
        flexibleStaffAuthenticationManager.update(authentication);
    }

    @Override
    @Transactional(transactionManager = "xpayCommonTransactionManager", rollbackFor = Exception.class)
    public void updateFlexibleStaffAuthentication(Long id) {
        Preconditions.checkArgument(id != null);
        FlexibleStaffAuthentication authentication = flexibleStaffAuthenticationManager.getById(id);

        AlipayFundFlexiblestaffingAuthenticationQueryModel model = new AlipayFundFlexiblestaffingAuthenticationQueryModel();
        model.setOutBizNo(authentication.getOutBizNo());
        try {
            AlipayFundFlexiblestaffingAuthenticationQueryResponse resp = xpaySafePayAlipayClient.queryAlipayFundFlexiblestaffingAuthentication(model);
            if (!resp.isSuccess()) {
                if ("IDENTITY_VERIFY_RECORD_NOT_EXIST".equals(resp.getSubCode())) {
                    //未核验
                    return;
                }
                log.warn("updateFlexibleStaffAuthentication failed resp={}|userId={}|authentication={}", SerializationUtil.obj2String(resp), authentication.getUserId(), SerializationUtil.obj2String(authentication));
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, resp.getSubMsg());
            }
            if ("SUCCESS".equals(resp.getVerifyResult())) {
                authentication.setVerifyResult(resp.getVerifyResult());
                authentication.setVerifyTime(LocalDateUtil.fromDate(resp.getVerifyTime()));
                flexibleStaffAuthenticationManager.update(authentication);

                //发起通知
                processNotify(authentication);
            }

        } catch (AlipayApiException e) {
            log.error("updateFlexibleStaffAuthentication error", e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "系统异常");
        }
    }

    private void processNotify(FlexibleStaffAuthentication authentication) {
        if (Strings.isNullOrEmpty(authentication.getNotifyUrl())) {
            return;
        }
        FlexibleStaffAuthenticationNotifyRecord record = new FlexibleStaffAuthenticationNotifyRecord();
        record.setUserId(authentication.getUserId());
        record.setImportBizNo(authentication.getImportBizNo());
        record.setFlexibleStaffAuthenticationId(authentication.getId());
        record.setStatus(NotifyStatus.WAIT);

        record.setNotifyUrl(authentication.getNotifyUrl());
        record.setNotifyCount(0);
        record.setNextNotifyTime(LocalDateTime.now());

        FlexibleStaffAuthenticationDto dto = new FlexibleStaffAuthenticationDto();
        dto.setImportBizNo(authentication.getImportBizNo());
        dto.setVerifyResult(authentication.getVerifyResult());
        dto.setVerifyTime(authentication.getVerifyTime());

        record.setNotifyContent(SerializationUtil.obj2String(dto));
        flexibleStaffAuthenticationNotifyRecordManager.save(record);

        //直接推送一下 减少延迟
        try {
            notifyRecord(record);
        } catch (Exception e) {
            log.info("processAuthenticationNotify failed|dto={}", SerializationUtil.obj2String(dto), e);
        }
    }

    public void notifyRecord(FlexibleStaffAuthenticationNotifyRecord record) {
        if (Strings.isNullOrEmpty(record.getNotifyUrl())) {
            return;
        }
        User user = userManager.getById(record.getUserId());

        List<NameValuePair> paramList = new ArrayList<>();
        NameValuePair appkey = new BasicNameValuePair("appkey", user.getAppkey());
        paramList.add(appkey);
        String time = System.currentTimeMillis() + "";
        NameValuePair timestamp = new BasicNameValuePair("timestamp", time);
        paramList.add(timestamp);
        NameValuePair signature = new BasicNameValuePair("signature", signerCheckHelper.sign(user.getAppkey(), user.getSecret(), time));
        paramList.add(signature);
        NameValuePair data = new BasicNameValuePair("data", record.getNotifyContent());
        paramList.add(data);

        String resp;
        try {
            HttpPost method = new HttpPost(record.getNotifyUrl());
            method.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8"));
            resp = HttpClientUtil.getInstance().executeAndGet(method, null, "UTF-8");
            log.info("notifyAuthenticationRecord|id={}|userId={}|resp={}", record.getImportBizNo(), record.getUserId(), resp);
            if (resp != null && "ok".equalsIgnoreCase(resp.trim())) {
                record.setStatus(NotifyStatus.OK);
                record.setNotifyCount(record.getNotifyCount() + 1);
                record.setEndTime(LocalDateTime.now());
                flexibleStaffAuthenticationNotifyRecordManager.update(record);
            } else {
                record.setNotifyCount(record.getNotifyCount() + 1);
                if (record.getNotifyCount() >= 8) {
                    record.setStatus(NotifyStatus.DEAD);
                    record.setEndTime(LocalDateTime.now());
                    flexibleStaffAuthenticationNotifyRecordManager.update(record);
                } else {
                    long[] minutes = new long[]{
                            2, 10, 10, 60, 120, 360, 900
                    };
                    record.setNextNotifyTime(record.getNextNotifyTime().plusMinutes(minutes[(record.getNotifyCount() - 1) % 7]));
                    flexibleStaffAuthenticationNotifyRecordManager.update(record);
                }
            }
        } catch (Throwable e) {
            log.error("doNotifyAuthenticationRecord error|id={}|userId={}", record.getImportBizNo(), record.getUserId(), e);
            record.setNotifyCount(record.getNotifyCount() + 1);
            if (record.getNotifyCount() >= 8) {
                record.setStatus(NotifyStatus.DEAD);
                record.setEndTime(LocalDateTime.now());
                flexibleStaffAuthenticationNotifyRecordManager.update(record);
            } else {
                long[] minutes = new long[]{
                        2, 10, 10, 60, 120, 360, 900
                };
                record.setNextNotifyTime(record.getNextNotifyTime().plusMinutes(minutes[(record.getNotifyCount() - 1) % 7]));
                flexibleStaffAuthenticationNotifyRecordManager.update(record);
            }
        }

    }

    private void doApplyFlexibleStaffAuthentication(FlexibleStaffAuthentication authentication) {
        AlipayFundFlexiblestaffingAuthenticationApplyModel param = new AlipayFundFlexiblestaffingAuthenticationApplyModel();
        ParticipantDTO partyInfo = new ParticipantDTO();
        param.setPrincipalInfo(partyInfo);
        partyInfo.setParticipantId(authentication.getIdentity());
        partyInfo.setParticipantIdType(authentication.getIdentityType());
        partyInfo.setName(authentication.getIdentityName()); //


        param.setOutBizNo(authentication.getOutBizNo());
        param.setApplyLinkType("SHORT_URL");
        param.setChannel("tinyapp");
        param.setExpireTime(LocalDateUtil.getDateTimeAsString(authentication.getApplyLinkExpireTime(), "yyyy-MM-dd HH:mm"));

        try {
            AlipayFundFlexiblestaffingAuthenticationApplyResponse response = xpaySafePayAlipayClient.applyAlipayFundFlexiblestaffingAuthentication(param);
            log.info("doApplyFlexibleStaffAuthentication resp={}", SerializationUtil.obj2String(response));
            if (!response.isSuccess()) {
                log.warn("doApplyFlexibleStaffAuthentication failed userId={}|authentication={}", authentication.getUserId(), SerializationUtil.obj2String(authentication));
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, response.getSubMsg());
            }
            authentication.setApplyLink(response.getApplyLink());
            authentication.setFlowToken(response.getFlowToken());
            String page = "pages/authentication/authentication?flowToken=" + authentication.getFlowToken();
            try {
                String url = "alipays://platformapi/startapp?appId=2021003198624012&page=" + URLEncoder.encode(page, "utf-8");
                String encodeUrl = "https://render.alipay.com/p/s/i/?scheme=" + URLEncoder.encode(url, "utf-8");
                authentication.setMiniAppApplyLink(encodeUrl);

            } catch (UnsupportedEncodingException e) {
                log.error("doApplyFlexibleStaffAuthentication error", e);
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "核身链接生成异常");
            }

        } catch (AlipayApiException e) {
            log.error("applyFlexibleStaffAuthentication error", e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "系统异常");
        }
    }

    private FlexibleStaffAuthentication buildAuthentication(User user, ApplyFlexibleStaffAuthenticationModel model) {
        FlexibleStaffAuthentication authentication = new FlexibleStaffAuthentication();
        authentication.setUserId(user.getId());

        authentication.setIdentity(model.getIdentity());
        authentication.setIdentityType(model.getIdentityType());
        authentication.setIdentityName(model.getIdentityName());
        authentication.setImportBizNo(model.getImportBizNo());
        authentication.setCardStatus(CardStatus.NO);
        authentication.setVerifyResult("INIT");
        authentication.setOutBizNo(GenIdUtil.getId("P", user.getId()));
        authentication.setApplyLinkExpireTime(LocalDateTime.now().plusHours(2L).withSecond(0)
                .withNano(0));

        authentication.setNotifyUrl(model.getNotifyUrl());
        authentication.setReturnUrl(model.getReturnUrl());

        return authentication;
    }


}
